package com.apple1.blogservices.impl;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.Email;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import com.apple1.blogdao.UserMapper;
import com.apple1.blogdao.UserRoleMapper;
import com.apple1.blogentity.User;
import com.apple1.blogentity.UserExample;
import com.apple1.blogentity.UserExample.Criteria;
import com.apple1.blogentity.UserRole;
import com.apple1.blogentity.form.UserForm;
import com.apple1.blogservices.UserService;
import com.apple1.commonutil.BeanMapUtil;
import com.apple1.commonutil.MD5Util;
import com.apple1.commonutil.MailUtil;
import com.apple1.commonutil.StringUtils;
import com.apple1.commonutil.common.ServerResponse;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import lombok.extern.slf4j.Slf4j;

/**
 *
 * @author huangliwei
 * @date   2019年1月20日
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
	
	/**
	 * 上传的图片文件保存的目录
	 */
	@Value("${blog.web.user.file-path}")
	private String filePath;
	
	@Autowired
	private UserMapper userMapper;
	
	@Autowired
	private UserRoleMapper userRoleMapper;

	@Override
    public Object login(User user, HttpServletRequest request) {
		Properties properties = new Properties();
		
		String userName = user.getUserName();
		String password = user.getPassword();
		// 校验字段
		if (StringUtils.isBlank(userName)) {
			return ServerResponse.failBack(properties, "用户名为空");
		}
		if (StringUtils.isBlank(password)) {
			return ServerResponse.failBack(properties, "密码为空");
		}		
        Subject subject = SecurityUtils.getSubject();
        User userTemp = userMapper.selectByUserName(userName);
        //用户状态这里不用管
    	if (userTemp == null) {
			return ServerResponse.failBack(properties, "该用户不存在");
		}
    	Integer loginFailCount = userTemp.getLoginFailCount();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), MD5Util.MD5EncodeUtf8(password + generateSalt2(userTemp.getSalt())));
        try {
            subject.login(token);
            //用户信息保存进session
            subject.getSession().setAttribute("userInfo", userTemp);
//            properties.put("token", subject.getSession().getId());
            properties.put("msg", "登录成功");
            //3次机会内登录成功清除错误记录
            User userTemp2 = new User();
            userTemp2.setLoginFailCount(0);
    		UserExample ex = new UserExample();
    		ex.createCriteria().andTableIdEqualTo(userTemp.getTableId());
    		userMapper.updateByExampleSelective(userTemp2, ex);
        } catch (IncorrectCredentialsException e) {
        	properties.put("msg", "密码错误");
        	properties.put("errCount", String.valueOf(loginFailCount + 1));
        	//记录错误次数，并处理
        	loginFailHander(userTemp);
        } catch (LockedAccountException e) {
        	properties.put("msg", "登录失败，该用户已被冻结");
        } catch (AuthenticationException e) {
        	properties.put("msg", "该用户不存在");
        } catch (AuthorizationException e) {
        	properties.put("msg", "add权限不存在");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return properties;
    }
	
	/**
	 * @param userTemp
	 */
	private void loginFailHander(User userTemp) {
		Integer loginFailCount = userTemp.getLoginFailCount();
		if(loginFailCount > 3) {
			return;
		}
		User user = new User();
		Integer loginFailCountNew = loginFailCount + 1;
		//错误次数>3次 锁定用户
		if(loginFailCountNew > 3) {
			user.setStatus(1);
		}
		user.setLoginFailCount(loginFailCountNew);
		UserExample ex = new UserExample();
		ex.createCriteria().andTableIdEqualTo(userTemp.getTableId());
		userMapper.updateByExampleSelective(user, ex);
	}

	@Override
	public Object register(UserForm model, MultipartFile file, HttpServletRequest request) {
		
		Properties properties = new Properties();
		
		String userName = model.getUserName();
		String password = model.getPassword();
		String mobilePhone = model.getMobilePhone();
		String emailValidCode = model.getEmailValidCode();
		String emailcode = (String)request.getSession().getAttribute("email_validCode");
		// 校验字段
		if (StringUtils.isBlank(userName)) {
			return ServerResponse.failBack(properties, "用户名为空");
		}
		if (StringUtils.isBlank(password)) {
			return ServerResponse.failBack(properties, "密码为空");
		}
		if (StringUtils.isBlank(mobilePhone)) {
			return ServerResponse.failBack(properties, "手机号为空");
		}
		if (StringUtils.isBlank(emailValidCode)) {
			return ServerResponse.failBack(properties, "验证码为空");
		}
		if(StringUtils.isBlank(emailcode)) {
			return ServerResponse.failBack(properties, "请先获取验证码");
		}
		if(!emailValidCode.equals(emailcode)) {
			return ServerResponse.failBack(properties, "验证码有误，请重新输入");
		}
		
		// 注册
		User user = BeanMapUtil.getMapBean(model, User.class);
		//校验用户是否已存在
		User userTemp = userMapper.selectByUserName(userName);
    	if (userTemp != null && userTemp.getStatus() != 3) {
			return ServerResponse.failBack(properties, "该用户名已注册");
		}
		
		String salt = generateSalt();
		user.setSalt(salt);
		user.setPassword(MD5Util.MD5EncodeUtf8(password + generateSalt2(salt)));
		//上传图片
		Properties upload = upload(file);
		if(!ServerResponse.isSuccess(upload)) {
			return upload;
		}
		user.setPicture(upload.getProperty("filePath"));
		user.setStatus(0);
		user.setLoginFailCount(0);
		//注册用户
		int count = userMapper.insertSelective(user);
		if(count <= 0) {
			return ServerResponse.failBack(properties, "注册失败");
		}
		//为用户关联默认角色
		UserRole userRole = new UserRole();
		userRole.setUserId(user.getTableId());
		//3普通用户
		userRole.setRoleId(3);
		userRoleMapper.insertSelective(userRole);
		return ServerResponse.successBack(properties,"注册成功");
	}
	
	/**
	 * @param salt
	 * @return
	 */
	private String generateSalt2(String salt) {
		return salt.charAt(2)+salt.charAt(13)+salt.charAt(10)+salt.charAt(4)+salt;
	}

	/**
	 * 自动生成盐值
	 * @return
	 */
	private String generateSalt(){
		Random r = new Random();
		StringBuilder sb = new StringBuilder(16);
		sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
		int len = sb.length();
		if (len < 16) {
			for (int i = 0; i < 16 - len; i++) {
				sb.append("0");
			}
		}
		return sb.toString();
	}
	
    public Properties upload(MultipartFile file) {
    	Properties properties = new Properties();
    	
        try {
            if (file.isEmpty()) {
                return ServerResponse.failBack(properties, "文件为空");
            }
            // 获取文件名
            String fileName = file.getOriginalFilename();
            log.info("上传的文件名为：" + fileName);
            // 获取文件的后缀名
            String suffixName = fileName.substring(fileName.lastIndexOf(".") + 1);
            log.info("文件的后缀名为：" + suffixName);
            String preName = fileName.substring(0,fileName.lastIndexOf("."));
            log.info("文件的简名（不包含后缀）为：" + preName);
            // 设置文件存储路径
            String path = filePath + fileName;
            File dest = new File(path);
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
            	// 新建文件夹
                dest.getParentFile().mkdirs();
            }
            // 文件写入
            file.transferTo(dest);
            properties.put("filePath", path);
            return ServerResponse.successBack(properties, "上传成功");
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ServerResponse.failBack(properties, "上传失败");
    }

	/* (non-Javadoc)
	 * @see com.apple1.blogservices.UserService#getUserInfo(java.lang.String)
	 */
	@Override
	public Object getUserInfo(String userName) {
		Properties properties = new Properties();
		User userTemp = userMapper.selectByUserName(userName);
        //用户状态这里不用管
    	if (userTemp == null) {
			return ServerResponse.failBack(properties, "该用户不存在");
		}
    	//过滤掉用户密码、盐值
    	userTemp.setPassword(null);
    	userTemp.setSalt(null);
    	properties.put("userInfo", userTemp);
		return properties;
	}


	/**
	 * TODO user的密码盐值 过滤
	 */
	@Override
	public Object getUserInfoList(int pageNum, int pageCount) {
		Properties properties = new Properties();
		PageHelper.startPage(pageNum, pageCount);
		List<User> userList = userMapper.selectByExample(null);
		properties.put("userList", userList);
		properties.put("total", ((Page)userList).getTotal());
		return ServerResponse.successBack(properties, "操作成功");
	}


	@Override
	public Object updateUserInfo(User user) {
		User userTemp = (User)SecurityUtils.getSubject().getSession().getAttribute("userInfo");
		Properties properties = new Properties();
		
		UserExample ex = new UserExample();
		ex.createCriteria().andTableIdEqualTo(userTemp.getTableId());
		int count = userMapper.updateByExampleSelective(user, ex);
		if(count > 0) {
			return ServerResponse.successBack(properties, "更新成功");
		}
		return ServerResponse.failBack(properties, "更新失败");
	}



	@Override
	public Object deleteUser(String userName) {
		Properties properties = new Properties();
		User user = new User();
		//暂且认定状态3（散了）是逻辑删除状态
		user.setStatus(3);
		UserExample ex = new UserExample();
		ex.createCriteria().andUserNameEqualTo(userName);
		int count = userMapper.updateByExampleSelective(user, ex);
		if(count > 0) {
			return ServerResponse.successBack(properties, "更新成功");
		}
		return ServerResponse.failBack(properties, "更新失败");
	}
	
	@Override
	public Object getEmailVaildCode(@Email String email, HttpServletRequest request) {
		Properties properties = new Properties();
		//1 generate code
		String vaildCode = generateSalt().substring(0, 6);
		log.info("登录邮箱验证码：{}", vaildCode);
		//save code to redis   session
		request.getSession().setAttribute("email_validCode", vaildCode);
		//2 send email
		MailUtil.send(email, "blog帐号--注册验证", vaildCode);
		return ServerResponse.successBack(properties);
	}
	
}
